import { ISA } from '@/atmosphere'
import { getBADAModel } from './core'
import type { BADAAircraftTypeModel, OperationPerformance } from './types'
import { ft2m, kt2Mps } from '@/widgets'

export interface FlightEnvelopeItem {
  alt: number
  cas: number
  tas: number
  mach: number
}

export interface FlightEnvelope {
  id: string
  minKCAS: {
    to: number
    ic: number
    cr: number
    ap: number
    ld: number
  }
  maxAltFt: number
  maxKCAS: number
  maxM: number
  minCAS: FlightEnvelopeItem[]
  maxAlt: FlightEnvelopeItem[]
  maxCAS: FlightEnvelopeItem[]
  maxMach: FlightEnvelopeItem[]
}

export const flightLevels = [
  0, 5, 10, 15, 20, 30, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 290, 310, 330,
  350, 370, 390, 410
]

export const airDataByFL = flightLevels.map((e) => ISA.getAirData(ft2m(e * 100)))

const maxToFL = 4
const maxIcFL = 20
// const maxAppFL = 80
// const maxLdFL = 30

// const hMaxTo = ft2m(400)
// const hMaxIc = ft2m(2000)
// const hMaxApp = ft2m(8000)
// const hMaxLd = ft2m(3000)
export const cVMin = 1.3 // cVMinTo = 1.2

export function calcClimbFlightEnvelopeById(id: string): FlightEnvelope {
  const model = getBADAModel(id)!
  return calcClimbFlightEnvelope(model)
}

export function calcClimbFlightEnvelope(model: BADAAircraftTypeModel): FlightEnvelope {
  const minCAS = calcClimbMinCAS(model.performance)
  const maxMach = calcClimbMaxMach(model.performance)
  const maxCAS = calcClimbMaxCAS(model.performance)
  const maxAlt = [minCAS[minCAS.length - 1], maxMach[maxMach.length - 1]]
  const maxKCAS = model.performance.vMO
  const maxM = model.performance.machMO
  const minKCAS = {
    to: model.performance.vStallTO * cVMin,
    ic: model.performance.vStallIC * cVMin,
    cr: model.performance.vStallCR * cVMin,
    ap: model.performance.vStallAP * cVMin,
    ld: model.performance.vStallLD * cVMin
  }
  const maxAltFt = model.performance.hMO
  return { id: model.id, maxAltFt, maxKCAS, maxM, minKCAS, minCAS, maxAlt, maxCAS, maxMach }
}

export function getKClimbStallCAS(op: OperationPerformance, fl: number): number {
  if (fl <= maxToFL) {
    return op.vStallTO
  }
  if (fl <= maxIcFL) {
    return op.vStallIC
  }
  return op.vStallCR
}

function calcClimbMaxCAS(op: OperationPerformance): FlightEnvelopeItem[] {
  const maxAlt = op.hMO
  const maxMach = op.machMO
  const cas = kt2Mps(op.vMO)
  let idx = 0
  let end = false
  const ret: FlightEnvelopeItem[] = []
  for (const fl of flightLevels) {
    const altFt = fl * 100
    if (altFt >= maxAlt) {
      break
    }
    const ad = airDataByFL[idx]
    const tas = ad.CAS2TAS(cas)
    const mach = ad.TAS2Mach(tas)

    const item: FlightEnvelopeItem = {
      alt: ft2m(altFt),
      cas,
      tas,
      mach
    }
    ret.push(item)
    if (mach >= maxMach) {
      end = true
      break
    }

    idx++
  }
  if (!end) {
    const alt = ft2m(maxAlt)
    const ad = ISA.getAirData(alt)
    const tas = ad.CAS2TAS(cas)
    const mach = ad.TAS2Mach(tas)

    const item: FlightEnvelopeItem = {
      alt,
      cas,
      tas,
      mach
    }
    ret.push(item)
  }
  return ret
}

function calcClimbMaxMach(op: OperationPerformance): FlightEnvelopeItem[] {
  const maxAlt = op.hMO
  const m = op.machMO
  let idx = 0
  const ret: FlightEnvelopeItem[] = []
  for (const fl of flightLevels) {
    const altFt = fl * 100
    if (altFt >= maxAlt) {
      break
    }
    const ad = airDataByFL[idx]
    const tas = ad.mach2TAS(m)
    const cas = ad.TAS2CAS(tas)

    const item: FlightEnvelopeItem = {
      alt: ft2m(altFt),
      cas,
      tas,
      mach: m
    }
    ret.push(item)

    idx++
  }
  const alt = ft2m(maxAlt)
  const ad = ISA.getAirData(alt)
  const tas = ad.mach2TAS(m)
  const cas = ad.TAS2CAS(tas)

  const item: FlightEnvelopeItem = {
    alt,
    cas,
    tas,
    mach: m
  }
  ret.push(item)
  return ret
}

function calcClimbMinCAS(op: OperationPerformance): FlightEnvelopeItem[] {
  const maxAlt = op.hMO
  let idx = 0
  const ret: FlightEnvelopeItem[] = []
  for (const fl of flightLevels) {
    const altFt = fl * 100
    if (altFt >= maxAlt) {
      break
    }
    const ad = airDataByFL[idx]
    const kStallCAS = getKClimbStallCAS(op, fl)
    const stallCAS = kt2Mps(kStallCAS)
    const minCAS = stallCAS * cVMin
    const minTAS = ad.CAS2TAS(minCAS)

    const item: FlightEnvelopeItem = {
      alt: ft2m(altFt),
      cas: minCAS,
      tas: minTAS,
      mach: ad.TAS2Mach(minTAS)
    }
    ret.push(item)

    idx++
  }
  const kStallCAS = getKClimbStallCAS(op, maxAlt / 100)
  const stallCAS = kt2Mps(kStallCAS)
  const minCAS = stallCAS * cVMin
  const alt = ft2m(maxAlt)
  const ad = ISA.getAirData(alt)
  const minTAS = ad.CAS2TAS(minCAS)

  const item: FlightEnvelopeItem = {
    alt,
    cas: minCAS,
    tas: minTAS,
    mach: ad.TAS2Mach(minTAS)
  }
  ret.push(item)

  return ret
}
